package thinkinjava1.ch14;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;

/**
 * Created by BobbyGu on 2017/2/27.
 */
//////////// The basic framework ///////////
class Blockable extends Thread {
    private Peeker peeker;
    protected TextField state = new TextField(40);
    protected int i;

    public Blockable(Container c) {
        c.add(state);
        peeker = new Peeker(this, c);
    }

    public synchronized int read() {
        return i;
    }

    protected synchronized void update() {
        state.setText(getClass().getName()
                + " state: i = " + i);
    }

    public void stopPeeker() {
// peeker.stop(); Deprecated in Java 1.2
        peeker.terminate(); // The preferred approach
    }
}

class Peeker extends Thread {
    private Blockable b;
    private int session;
    private TextField status = new TextField(40);
    private boolean stop = false;

    public Peeker(Blockable b, Container c) {
        c.add(status);
        this.b = b;
        start();
    }

    public void terminate() {
        stop = true;
    }

    public void run() {
        while (!stop) {
            status.setText(b.getClass().getName()
                    + " Peeker " + (++session)
                    + "; value = " + b.read());
            try {
                sleep(100);
            } catch (InterruptedException e) {
            }
        }
    }
}

//1. 睡眠
///////////// Blocking via sleep() ///////////
class Sleeper1 extends Blockable {
    public Sleeper1(Container c) {
        super(c);
    }

    public synchronized void run() {
        while (true) {
            i++;
            update();
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

class Sleeper2 extends Blockable {
    public Sleeper2(Container c) {
        super(c);
    }

    public void run() {
        while (true) {
            change();
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }

    public synchronized void change() {
        i++;
        update();
    }
}

//2. 暂停和恢复
/////////// Blocking via suspend() ///////////
class SuspendResume extends Blockable {
    public SuspendResume(Container c) {
        super(c);
        new Resumer(this);
    }
}

class SuspendResume1 extends SuspendResume {
    public SuspendResume1(Container c) {
        super(c);
    }

    public synchronized void run() {
        while (true) {
            i++;
            update();
            suspend(); // Deprecated in Java 1.2
        }
    }
}

class SuspendResume2 extends SuspendResume {
    public SuspendResume2(Container c) {
        super(c);
    }

    public void run() {
        while (true) {
            change();
            suspend(); // Deprecated in Java 1.2
        }
    }

    public synchronized void change() {
        i++;
        update();
    }
}

class Resumer extends Thread {
    private SuspendResume sr;

    public Resumer(SuspendResume sr) {
        this.sr = sr;
        start();
    }

    public void run() {
        while (true) {
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
            sr.resume(); // Deprecated in Java 1.2
        }
    }
}

//3. 等待和通知
/////////// Blocking via wait() ///////////
class WaitNotify1 extends Blockable {
    public WaitNotify1(Container c) {
        super(c);
    }

    public synchronized void run() {
        while (true) {
            i++;
            update();
            try {
                wait(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

class WaitNotify2 extends Blockable {
    public WaitNotify2(Container c) {
        super(c);
        new Notifier(this);
    }

    public synchronized void run() {
        while (true) {
            i++;
            update();
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
}

class Notifier extends Thread {
    private WaitNotify2 wn2;

    public Notifier(WaitNotify2 wn2) {
        this.wn2 = wn2;
        start();
    }

    public void run() {
        while (true) {
            try {
                sleep(2000);
            } catch (InterruptedException e) {
            }
            synchronized (wn2) {
                wn2.notify();
            }
        }
    }
}

//4. IO 堵塞
class Sender extends Blockable { // send516
    private Writer out;

    public Sender(Container c, Writer out) {
        super(c);
        this.out = out;
    }

    public void run() {
        while (true) {
            for (char c = 'A'; c <= 'z'; c++) {
                try {
                    i++;
                    out.write(c);
                    state.setText("Sender sent: "
                            + (char) c);
                    sleep((int) (3000 * Math.random()));
                } catch (InterruptedException e) {
                } catch (IOException e) {
                }
            }
        }
    }
}

class Receiver extends Blockable {
    private Reader in;

    public Receiver(Container c, Reader in) {
        super(c);
        this.in = in;
    }

    public void run() {
        try {
            while (true) {
                i++; // Show peeker it's alive
// Blocks until characters are there:
                state.setText("Receiver read: "
                        + (char) in.read());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/////////// Testing Everything ///////////
public class Blocking extends Applet {
    private Button
            start = new Button("Start"),
            stopPeekers = new Button("Stop Peekers");
    private boolean started = false;
    private Blockable[] b;
    private PipedWriter out;
    private PipedReader in;

    public void init() {
        out = new PipedWriter();
        try {
            in = new PipedReader(out);
        } catch (IOException e) {
        }
        b = new Blockable[]{
                new Sleeper1(this),
                new Sleeper2(this),
                new SuspendResume1(this),
                new SuspendResume2(this),
                new WaitNotify1(this),
                new WaitNotify2(this),
                new Sender(this, out),
                new Receiver(this, in)
        };
        start.addActionListener(new StartL());
        add(start);
        stopPeekers.addActionListener(
                new StopPeekersL());
        add(stopPeekers);
    }

    class StartL implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            if (!started) {
                started = true;
                for (int i = 0; i < b.length; i++)
                    b[i].start();
            }
        }
    }

    class StopPeekersL implements ActionListener {
        public void actionPerformed(ActionEvent e) {
// Demonstration of the preferred
// alternative to Thread.stop():
            for (int i = 0; i < b.length; i++)
                b[i].stopPeeker();
        }
    }

    public static void main(String[] args) {
        Blocking applet = new Blocking();
        Frame aFrame = new Frame("Blocking");
        aFrame.addWindowListener(
                new WindowAdapter() {
                    public void windowClosing(WindowEvent e) {
                        System.exit(0);
                    }
                });
        aFrame.add(applet, BorderLayout.CENTER);
        aFrame.setSize(350, 550);
        applet.init();
        applet.start();
        aFrame.setVisible(true);
    }
}